{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Fashion MNIST"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### After downloading our dataset we see it's coded in the ubyte form\n",
    "- We then use the following function to read the data and return it as a numpy array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import struct\n",
    "import numpy as np\n",
    "\n",
    "def read_idx(filename):\n",
    "    \"\"\"Credit: https://gist.github.com/tylerneylon\"\"\"\n",
    "    with open(filename, 'rb') as f:\n",
    "        zero, data_type, dims = struct.unpack('>HBB', f.read(4))\n",
    "        shape = tuple(struct.unpack('>I', f.read(4))[0] for d in range(dims))\n",
    "        return np.frombuffer(f.read(), dtype=np.uint8).reshape(shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### We use the function to extact our training and test datasets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = read_idx(\"./fashion_mnist/train-images-idx3-ubyte\")\n",
    "y_train = read_idx(\"./fashion_mnist/train-labels-idx1-ubyte\")\n",
    "x_test = read_idx(\"./fashion_mnist/t10k-images-idx3-ubyte\")\n",
    "y_test = read_idx(\"./fashion_mnist/t10k-labels-idx1-ubyte\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's inspect our dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial shape or dimensions of x_train (60000, 28, 28)\n",
      "Number of samples in our training data: 60000\n",
      "Number of labels in our training data: 60000\n",
      "Number of samples in our test data: 10000\n",
      "Number of labels in our test data: 10000\n",
      "\n",
      "Dimensions of x_train:(28, 28)\n",
      "Labels in x_train:(60000,)\n",
      "\n",
      "Dimensions of x_test:(28, 28)\n",
      "Labels in y_test:(10000,)\n"
     ]
    }
   ],
   "source": [
    "# printing the number of samples in x_train, x_test, y_train, y_test\n",
    "print(\"Initial shape or dimensions of x_train\", str(x_train.shape))\n",
    "\n",
    "print (\"Number of samples in our training data: \" + str(len(x_train)))\n",
    "print (\"Number of labels in our training data: \" + str(len(y_train)))\n",
    "print (\"Number of samples in our test data: \" + str(len(x_test)))\n",
    "print (\"Number of labels in our test data: \" + str(len(y_test)))\n",
    "print()\n",
    "print (\"Dimensions of x_train:\" + str(x_train[0].shape))\n",
    "print (\"Labels in x_train:\" + str(y_train.shape))\n",
    "print()\n",
    "print (\"Dimensions of x_test:\" + str(x_test[0].shape))\n",
    "print (\"Labels in y_test:\" + str(y_test.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's view some sample images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 6 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's do the same thing but using matplotlib to plot 6 images \n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Plots 6 images, note subplot's arugments are nrows,ncols,index\n",
    "# we set the color map to grey since our image dataset is grayscale\n",
    "plt.subplot(331)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "plt.subplot(332)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "plt.subplot(333)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "plt.subplot(334)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "plt.subplot(335)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "plt.subplot(336)\n",
    "random_num = np.random.randint(0,len(x_train))\n",
    "plt.imshow(x_train[random_num], cmap=plt.get_cmap('gray'))\n",
    "\n",
    "# Display out plots\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's create our model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x_train shape: (60000, 28, 28, 1)\n",
      "60000 train samples\n",
      "10000 test samples\n",
      "Number of Classes: 10\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d_5 (Conv2D)            (None, 26, 26, 32)        320       \n",
      "_________________________________________________________________\n",
      "batch_normalization_7 (Batch (None, 26, 26, 32)        128       \n",
      "_________________________________________________________________\n",
      "conv2d_6 (Conv2D)            (None, 24, 24, 64)        18496     \n",
      "_________________________________________________________________\n",
      "batch_normalization_8 (Batch (None, 24, 24, 64)        256       \n",
      "_________________________________________________________________\n",
      "max_pooling2d_3 (MaxPooling2 (None, 12, 12, 64)        0         \n",
      "_________________________________________________________________\n",
      "dropout_5 (Dropout)          (None, 12, 12, 64)        0         \n",
      "_________________________________________________________________\n",
      "flatten_3 (Flatten)          (None, 9216)              0         \n",
      "_________________________________________________________________\n",
      "dense_5 (Dense)              (None, 128)               1179776   \n",
      "_________________________________________________________________\n",
      "batch_normalization_9 (Batch (None, 128)               512       \n",
      "_________________________________________________________________\n",
      "dropout_6 (Dropout)          (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_6 (Dense)              (None, 10)                1290      \n",
      "=================================================================\n",
      "Total params: 1,200,778\n",
      "Trainable params: 1,200,330\n",
      "Non-trainable params: 448\n",
      "_________________________________________________________________\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "from keras.datasets import mnist\n",
    "from keras.utils import np_utils\n",
    "import keras\n",
    "from keras.datasets import mnist\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense, Dropout, Flatten\n",
    "from keras.layers import Conv2D, MaxPooling2D, BatchNormalization\n",
    "from keras import backend as K\n",
    "\n",
    "# Training Parameters\n",
    "batch_size = 128\n",
    "epochs = 1\n",
    "\n",
    "# Lets store the number of rows and columns\n",
    "img_rows = x_train[0].shape[0]\n",
    "img_cols = x_train[1].shape[0]\n",
    "\n",
    "# Getting our date in the right 'shape' needed for Keras\n",
    "# We need to add a 4th dimenion to our date thereby changing our\n",
    "# Our original image shape of (60000,28,28) to (60000,28,28,1)\n",
    "x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)\n",
    "x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)\n",
    "\n",
    "# store the shape of a single image \n",
    "input_shape = (img_rows, img_cols, 1)\n",
    "\n",
    "# change our image type to float32 data type\n",
    "x_train = x_train.astype('float32')\n",
    "x_test = x_test.astype('float32')\n",
    "\n",
    "# Normalize our data by changing the range from (0 to 255) to (0 to 1)\n",
    "x_train /= 255\n",
    "x_test /= 255\n",
    "\n",
    "print('x_train shape:', x_train.shape)\n",
    "print(x_train.shape[0], 'train samples')\n",
    "print(x_test.shape[0], 'test samples')\n",
    "\n",
    "# Now we one hot encode outputs\n",
    "y_train = np_utils.to_categorical(y_train)\n",
    "y_test = np_utils.to_categorical(y_test)\n",
    "\n",
    "# Let's count the number columns in our hot encoded matrix \n",
    "print (\"Number of Classes: \" + str(y_test.shape[1]))\n",
    "\n",
    "num_classes = y_test.shape[1]\n",
    "num_pixels = x_train.shape[1] * x_train.shape[2]\n",
    "\n",
    "# create model\n",
    "model = Sequential()\n",
    "\n",
    "model.add(Conv2D(32, kernel_size=(3, 3),\n",
    "                 activation='relu',\n",
    "                 input_shape=input_shape))\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "model.add(Conv2D(64, (3, 3), activation='relu'))\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "model.add(MaxPooling2D(pool_size=(2, 2)))\n",
    "model.add(Dropout(0.25))\n",
    "\n",
    "model.add(Flatten())\n",
    "model.add(Dense(128, activation='relu'))\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "model.add(Dropout(0.5))\n",
    "model.add(Dense(num_classes, activation='softmax'))\n",
    "\n",
    "model.compile(loss = 'categorical_crossentropy',\n",
    "              optimizer = keras.optimizers.Adadelta(),\n",
    "              metrics = ['accuracy'])\n",
    "\n",
    "print(model.summary())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's train our model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 60000 samples, validate on 10000 samples\n",
      "Epoch 1/1\n",
      "60000/60000 [==============================] - 333s 6ms/step - loss: 0.4568 - acc: 0.8438 - val_loss: 0.3048 - val_acc: 0.8927\n",
      "Test loss: 0.30478706385493276\n",
      "Test accuracy: 0.8927\n"
     ]
    }
   ],
   "source": [
    "history = model.fit(x_train, y_train,\n",
    "          batch_size=batch_size,\n",
    "          epochs=epochs,\n",
    "          verbose=1,\n",
    "          validation_data=(x_test, y_test))\n",
    "\n",
    "score = model.evaluate(x_test, y_test, verbose=0)\n",
    "print('Test loss:', score[0])\n",
    "print('Test accuracy:', score[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Let's test out our model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "\n",
    "def getLabel(input_class):\n",
    "    number = int(input_class)\n",
    "    if number == 0:\n",
    "        return \"T-shirt/top \"\n",
    "    if number == 1:\n",
    "        return \"Trouser\"\n",
    "    if number == 2:\n",
    "        return \"Pullover\"\n",
    "    if number == 3:\n",
    "        return \"Dress\"\n",
    "    if number == 4:\n",
    "        return \"Coat\"\n",
    "    if number == 5:\n",
    "        return \"Sandal\"\n",
    "    if number == 6:\n",
    "        return \"Shirt\"\n",
    "    if number == 7:\n",
    "        return \"Sneaker\"\n",
    "    if number == 8:\n",
    "        return \"Bag\"\n",
    "    if number == 9:\n",
    "        return \"Ankle boot\"\n",
    "\n",
    "def draw_test(name, pred, actual, input_im):\n",
    "    BLACK = [0,0,0]\n",
    "\n",
    "    res = getLabel(pred)\n",
    "    actual = getLabel(actual)   \n",
    "    expanded_image = cv2.copyMakeBorder(input_im, 0, 0, 0, 4*imageL.shape[0] ,cv2.BORDER_CONSTANT,value=BLACK)\n",
    "    expanded_image = cv2.cvtColor(expanded_image, cv2.COLOR_GRAY2BGR)\n",
    "    cv2.putText(expanded_image, \"Predicted - \" + str(res), (152, 70) , cv2.FONT_HERSHEY_COMPLEX_SMALL,1, (0,255,0), 1)\n",
    "    cv2.putText(expanded_image, \"   Actual - \" + str(actual), (152, 90) , cv2.FONT_HERSHEY_COMPLEX_SMALL,1, (0,0,255), 1)\n",
    "    cv2.imshow(name, expanded_image)\n",
    "\n",
    "\n",
    "for i in range(0,10):\n",
    "    rand = np.random.randint(0,len(x_test))\n",
    "    input_im = x_test[rand]\n",
    "    actual = y_test[rand].argmax(axis=0)\n",
    "    imageL = cv2.resize(input_im, None, fx=4, fy=4, interpolation = cv2.INTER_CUBIC)\n",
    "    input_im = input_im.reshape(1,28,28,1) \n",
    "    \n",
    "    ## Get Prediction\n",
    "    res = str(model.predict_classes(input_im, 1, verbose = 0)[0])\n",
    "\n",
    "    draw_test(\"Prediction\", res, actual, imageL) \n",
    "    cv2.waitKey(0)\n",
    "\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
